package com.anycc.cloud.core.service.impl;

import com.anycc.cloud.common.dto.easyui.Tree;
import com.anycc.cloud.common.dto.easyui.TreeBuilder;
import com.anycc.cloud.common.dto.query.PagingRequest;
import com.anycc.cloud.common.dto.query.PagingResponse;
import com.anycc.cloud.common.exception.AnyccRuntimeException;
import com.anycc.cloud.common.util.DynamicQuery;
import com.anycc.cloud.common.util.PagingUtil;
import com.anycc.cloud.common.util.PatternUtil;
import com.anycc.cloud.core.entity.Area;
import com.anycc.cloud.core.repository.AreaRepository;
import com.anycc.cloud.core.service.AreaService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Optional;

import static com.anycc.cloud.common.constant.CacheNameConstant.*;

/**
 * area service实现类
 */
@Service
public class AreaServiceImpl implements AreaService {
    @Autowired
    private AreaRepository areaRepository;
    private TreeBuilder<Area> areaTreeBuilder = new AreaServiceImpl.AreaTreeBuilder();

    @Override
    public Area create(Area area) {
        this.checkAreaNameAndCode(area);
        Assert.isNull(area.getId(), "创建区划时，区划ID必须为空");
        calculateAreaLevel(area);
        return areaRepository.save(area);
    }

    @Override
    @CacheEvict(value = {FIELD_CACHE_AREA_TREE},allEntries=true)//allEntries表示清除该key下所有元素
    public Area update(Area area) {
        checkAreaNameAndCode(area);
        Assert.notNull(area.getId(), "更新区划时，区划ID不能为空");
        return areaRepository.save(area);
    }

    @Override
    @CacheEvict(value = {FIELD_CACHE_AREA_TREE},allEntries=true)//allEntries表示清除该key下所有元素
    public void delete(String id) {
        Assert.notNull(id, "删除区划时，区划ID不能为空");
        areaRepository.deleteById(id);
    }

    @Override
    public Area findById(String id) {
        Assert.notNull(id, "根据区划ID查询区划信息时，区划ID不能为空");
        Optional<Area> optional = areaRepository.findById(id);
        return optional.orElse(null);
    }

    @Override
    public Area findByCode(String code) {
        return areaRepository.findByCode(code);
    }

    @Override
    public PagingResponse<Area> findByPaging(Area area, PagingRequest pagingRequest) {
        Page<Area> page = areaRepository
                .findAll(new DynamicQuery<Area>().build((predicates, root, query, cb) -> {
                    if (StringUtils.isNotBlank(area.getName())) {
                        predicates.add(cb.like(root.get(Area.FIELD_NAME), PatternUtil.trimLike(area.getName())));
                    }
                    Optional.ofNullable(area.getParent()).ifPresent(parent ->
                            predicates.add(cb.equal(root.get(Area.FIELD_PARENT).get(Area.FIELD_ID), parent.getId()))
                    );
                }), PagingUtil.buildPageRequest(pagingRequest));
        return PagingUtil.buildPagingResponse(pagingRequest, page);
    }

    @Override
    @Cacheable(value = FIELD_CACHE_AREA_TREE, key = "'area' +'_'+ #root.method.name")
    public List<Tree> tree() {
        return areaTreeBuilder.buildTreeList(areaRepository.findAll(Sort.by(Sort.Direction.ASC, "code", "name")));
    }

    @Override
    public List<Tree> parentTree(String areaId) {
        Area currentOrg = areaRepository.findById(areaId).orElse(null);
        Assert.notNull(currentOrg, "机构树当前机构不能为空");
        return areaTreeBuilder.buildParentTreeList(areaRepository.findAll(Sort.by(Sort.Direction.ASC, "code", "name")), currentOrg);
    }

    private void calculateAreaLevel(Area area) {
        Integer level = 1;
        while (area.getParent() != null) {
            level++;
            area = area.getParent();
        }
        area.setLevelNum(level);
    }

    private void checkAreaNameAndCode(Area area) {
        if (area != null && !StringUtils.isBlank(area.getName())) {
            if (StringUtils.isNotBlank(area.getCode())) {
                Area dbArea = findByCode(area.getCode());
                if (dbArea != null && !StringUtils.equals(dbArea.getId(), area.getId())) {
                    throw new AnyccRuntimeException("core.exceptions.area.code_existed");
                }
            }
        } else {
            throw new AnyccRuntimeException("core.exceptions.area.name_required");
        }
    }

    private class AreaTreeBuilder extends TreeBuilder<Area> {//工厂方法模式子类

        private AreaTreeBuilder() {
        }

        protected Area getParent(Area entity) {
            return entity.getParent();
        }

        protected List<Area> getChildren(Area entity) {
            return entity.getChildren();
        }

        protected String getNodeId(Area entity) {
            return entity.getId();
        }

        protected String getNodeText(Area entity) {
            return entity.getName();
        }
    }


}
